{
 "cells": [
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "### 频数分布表\n",
    "\n",
    "定义：频数分布表是通过展示数据类别（或组）以及每个类别中数据值的数量（频数），显示数据是如何在不同类别（或组）间划分的\n",
    "\n",
    "相关概念：\n",
    "- 组下限：能够被分配到每个不同组的原始值的**最小值**\n",
    "- 组上限：能够被分配到每个不同组的原始值的**最大值**\n",
    "- 组界：分隔一个组结束和下一个组开始之间的差值\n",
    "- 组中值：每组中间的值\n",
    "- 组距：两个连续组下限之间的差值\n",
    "\n",
    "构建频数分布表的目的：\n",
    "1. 汇总大型数据集\n",
    "2. 查看数据分布\n",
    "3. 识别异常值\n",
    "4. 为构建图表提供基础\n",
    "\n",
    "构建频数分布表的流程：\n",
    "1. 选择分组数目\n",
    "2. 计算组距\n",
    "3. 选择最小值或低于最小值的某一个较为方便使用的值作为第一组的下限\n",
    "4. 通过第一组的下限与组距，得到其他组的下限\n",
    "5. 确定所有组的上限\n",
    "6. 求每组的频数\n",
    "\n",
    "原则：\n",
    "1. 每个原始值只属于其中一个组，各组之间不重叠\n",
    "2. 尽可能对所有组使用相同的组距\n",
    "\n",
    "\n",
    "### 相对频数分布表\n",
    "\n",
    "定义：每组的频数使用相对频数或百分比代替，是频数分布表的一种变形\n",
    "\n",
    "每组相对频数 = $\\frac{组频数}{}$，每组百分比 = $\\frac{组频数}{总频数} × 100\\%$\n",
    "\n",
    "原则：\n",
    "1. 相对频数分布表的百分比之和必须非常接近100%，因四舍五入导致的误差可以接受\n",
    "\n",
    "\n",
    "### 累计频数分布表\n",
    "\n",
    "定义：每组的频数是该组频数与前面所有组的频数之和，是频数分布表的一种变形"
   ],
   "id": "e4c7a755d12824d7"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-10-25T09:41:40.084110Z",
     "start_time": "2025-10-25T09:41:40.067760Z"
    }
   },
   "cell_type": "code",
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "\n",
    "# 随机生成 50 条数据\n",
    "bins = [0, 15, 30, 45, 60, 75, 90, 105]        # 左闭右开\n",
    "freq = [6, 18, 14, 5, 5, 1, 1]\n",
    "np.random.seed(42)\n",
    "data = []\n",
    "for left, right, n in zip(bins[:-1], bins[1:], freq):\n",
    "    data.extend(np.random.randint(left, right, size=n))\n",
    "data = pd.Series(data, name='data')\n",
    "\n",
    "# 频数分布表\n",
    "dist = pd.cut(data, bins=bins, right=False)  # 左闭右开\n",
    "freq_table = dist.value_counts().sort_index()\n",
    "# 相对频数\n",
    "rel_freq = dist.value_counts(normalize=True).sort_index() * 100\n",
    "# 累计频数\n",
    "cum_freq = freq_table.cumsum()\n",
    "# 累计相对频数\n",
    "cum_rel = cum_freq / freq_table.sum()\n",
    "\n",
    "result = pd.DataFrame({\n",
    "    '频数': freq_table,\n",
    "    '相对百分比(%)': rel_freq,\n",
    "    '累计相对频数': cum_freq,\n",
    "    '累计相对百分比(%)': cum_rel\n",
    "})\n",
    "\n",
    "print(result)\n",
    "\n",
    "#dist_in_ex = pd.cut(data, bins=bins, right=False)  # 左闭右开\n",
    "#freq_in_ex = dist_in_ex.value_counts().sort_index()\n"
   ],
   "id": "de7047228323ed91",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "           频数  相对百分比(%)  累计相对频数  累计相对百分比(%)\n",
      "data                                       \n",
      "[0, 15)     6      12.0       6        0.12\n",
      "[15, 30)   18      36.0      24        0.48\n",
      "[30, 45)   14      28.0      38        0.76\n",
      "[45, 60)    5      10.0      43        0.86\n",
      "[60, 75)    5      10.0      48        0.96\n",
      "[75, 90)    1       2.0      49        0.98\n",
      "[90, 105)   1       2.0      50        1.00\n"
     ]
    }
   ],
   "execution_count": 21
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
